package sllvm;
import sll.AssignStm;
import sll.CompoundStm;
import sll.EseqExp;
import sll.Exp;
import sll.ExpList;
import sll.LastExpList;
import sll.OpExp;
import sll.PairExpList;
import sll.PrintStm;
import sll.Stm;

public class Interpreter
{
	public static int maxargs(Stm s)
	{
		int max;
		
		// descobrimos o tipo de statement que recebemos
		if (s instanceof CompoundStm)
		{
			// se for um compound, obtemos por recursao o maior valor
			CompoundStm cStm = (CompoundStm)s;			
			max = Math.max(maxargs(cStm.stm1), maxargs(cStm.stm2));
		}
		else if (s instanceof AssignStm)
		{
			// se for um assignment temos um método para lidar com exps
			AssignStm aStm = (AssignStm)s; 
			// assignStm nunca estará diretamente dentro de um print
			// apenas indiretamente através de um eseqExp contendo um assignStm
			max = maxargs(aStm.exp);
		}
		else if (s instanceof PrintStm)
		{
			// se for um print
			PrintStm pStm = (PrintStm)s;
			// retorna o maior valor entre
			// o numero de argumentos deste print e o maior numero de argumentos de algum print dentro das exps
			max = Math.max(pStm.exps.count(), maxargs(pStm.exps));
		}
		else
			max = 0; // nao existe print
		
		return max;
	}

	private static int maxargs(ExpList e)
	{
		int max;
		
		if (e instanceof LastExpList)
		{
			// se chegamos ao final
			LastExpList le = (LastExpList)e;					
			// calculamos quantidade de argumentos da exp e decimos qual é a maior
			max = maxargs(le.head);
		}
		else
		{
			// se for final da lista, eh um par (meio lisp isso...)
			PairExpList pe = (PairExpList)e;
			// analisamos cada parte e pegamos a maior
			max = Math.max(maxargs(pe.head), maxargs(pe.tail));
		}
		
		return max;
	}

	
	/**
	 * Calcula maior número de argumentos de algum print pertencente a e.
	 * @param e
	 * @return maior número de argumentos de algum print dentro de e. -1 caso contário
	 */
	private static int maxargs(Exp e)
	{
		int max;
		
		if (e instanceof EseqExp)
		{
			// o unico meio de existir um print aqui eh usando EseqExp que possui um Stm
			EseqExp esx = (EseqExp)e;
			
			// pode existir um print dentro de esx.stm ou de esx.exp, vamos olhar os dois 
			max = Math.max(maxargs(esx.exp), maxargs(esx.stm));
		}
		else if (e instanceof OpExp)
		{
			OpExp ox = (OpExp)e;
			
			// pode haver um EseqExp dentro de ox.left ou ox.right 
			max = Math.max(maxargs(ox.left), maxargs(ox.right));
		}
		else
			max = 0; // nao ha print aqui
		
		return max;
	}
	
	public static void interpret(Stm s)
	{
		System.out.println("DEBUG: Interpreter start.");
		
		// dummy start table
		Table t = new Table("void", 0);		
		s.interpretate(t);
		
		System.out.println("DEBUG: Interpreter end.");
	}
}
